Java方法调用mapper方法,代码如下所示
1 | public static void init() { |
获取maaper代理类源码分析, 以下代码只分析其主要方法,不重要的忽略,
1 | //DefaultSqlSession 类 |
mapper执行语句分析
通过上一节,得知如何获取mapper代理类,本节分析mapper如何执行sql
上节得知通过反射Proxy.newProxyInstance()创建mapper代理类的InvocationHandler的参数为mapperProxy,该参数作用为所有代理类的方法调用必须invoke(),下面分析MapperProxy.invoke()方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65// MapperProxy.class
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// proxy实例对象,method执行方法,args,参数
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
MapperMethod mapperMethod = this.cachedMapperMethod(method); //获取MapperMethod,如果缓存中直接获取,没有创建并加入缓存
return mapperMethod.execute(this.sqlSession, args);// mapper类所有方法最终执行execute方法
}
// MapperMethod.class 构造方法,为两个属性赋值,sqlCommand 中保存了一些和 SQL 相关的信息,MethodSignature 即方法签名,顾名思义,该类保存了一些和目标方法相关的信息。比如目标方法的返回类型,目标方法的参数列表信息等。
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
}
// MapperMethod.SqlCommand.class 构造方法,从configuration中获取SqlCommandType、name,name为方法名,sqlConmandatype即UNKNOWN,INSERT,UPDATE,DELETE,SELECT,FLUSH;该值初始化configuration时在解析mapper节点时赋值
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
String methodName = method.getName();
Class<?> declaringClass = method.getDeclaringClass();
MappedStatement ms = this.resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) == null) {
throw new BindingException("Invalid bound statement (not found): " + mapperInterface.getName() + "." + methodName);
}
this.name = null;
this.type = SqlCommandType.FLUSH;
} else {
this.name = ms.getId();
this.type = ms.getSqlCommandType();
if (this.type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + this.name);
}
}
}
// MapperMethod.MethodSignature 方法签名
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class) {
this.returnType = (Class)resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class)((ParameterizedType)resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
this.returnsVoid = Void.TYPE.equals(this.returnType);
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.mapKey = this.getMapKey(method);
this.returnsMap = this.mapKey != null;
this.rowBoundsIndex = this.getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = this.getUniqueParamIndex(method, ResultHandler.class);
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
mapper执行sql语句
1 |
|
总结
总结下映射器的调用过程,返回的Mapper对象是代理对象,当调用它的某个方法时,其实是调用MapperProxy#invoke方法,而映射器的XML文件的命名空间对应的就是这个接口的全路径,会根据全路径和方法名,便能够绑定起来,定位到sql,最后会使用SqlSession接口的方法使它能够执行查询。
解析:XMLMapperBuilder 解析标签
标签内容,与XMLConfigBuilder类似,XMLConfigBuilder解析 标签 将mapper与configuration绑定:通过XMLMapperBuilder.configurationElement()解析mapper内容,并生成 MapperStatement 添加到 Configuration 中;使用namespace名称通过bindMapperForNamespace(),将mapper绑定到Configuration中mapperRegistry参数中,MapperRegistry 类是一个 Mapper 类注册工厂,把与 MapperProxyFactory 映射过的 Mapper 类添加到它的属性 knownMappers 中;,类型为Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
获取mapper:当调用session.getMapper(Class
type)方法时,实际调用的是MapperRegisty注册工厂,通过class获取的MapperProxyFactory,并通过反射与session关联生成mapper代理类,所以调用mapper所有方法都会调用MapperProxy.invoke(),再根据sql配置进行对应sql执行